using System;
using System.Runtime.InteropServices;

namespace CBox_GUI
{
    internal class DllInject
    {

        [DllImport("kernel32")] // Creatign a remote thread.
        private static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize,
                                                       UIntPtr lpStartAddress,
                                                       IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);

        [DllImport("kernel32.dll")] // To get process handle
        private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId);

        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] // Allocating virtual memory.
        private static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType,
                                                    uint flProtect);

        [DllImport("kernel32.dll")]
        private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, string lpBuffer, UIntPtr nSize,
                                                      IntPtr lpNumberOfBytesWritten);

        [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true)]
        private static extern UIntPtr GetProcAddress(IntPtr hModule, string procName);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);

        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
        private static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress,
                                                 int dwSize, FreeType dwFreeType);

        [Flags]
        private enum FreeType
        {
            Decommit = 0x4000,
            Release = 0x8000,
        }

        public static bool Inject(string dll, string process)
        {
            IntPtr bout = IntPtr.Zero;

            int pID = System.Diagnostics.Process.GetProcessesByName(process)[0].Id; // Process ID
            IntPtr hprocess = OpenProcess(0x001F0FFF, true, pID); // Process Handle
            if (hprocess != IntPtr.Zero)
            {
                int Size = dll.Length;

                IntPtr mAdd = VirtualAllocEx(hprocess, IntPtr.Zero, (uint) Size, 0x1000 | 0x2000, 0x04);
                // Allocating memory
                if (mAdd != IntPtr.Zero)
                {
                    if (WriteProcessMemory(hprocess, mAdd, dll, (UIntPtr) Size, bout))
                    {
                        UIntPtr x = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
                        if (x != UIntPtr.Zero)
                        {
                            IntPtr rThread = CreateRemoteThread(hprocess, IntPtr.Zero, (uint) 0, x, mAdd, (uint) 0, bout);

                            if (WaitForSingleObject(rThread, 0xFFFFFFFF) == 0x00000000)
                            {
                                VirtualFreeEx(hprocess, mAdd, Size, FreeType.Release);
                            }
                            return true;
                        }
                    }
                }
            }
            return false;
        }
    }
}